/**
 * Project: springyounger.lottery.biz.user
 * 
 * File Created at 2010-3-26
 * $Id$
 * 
 * Copyright 2009 Zjut Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Zjut Edu. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Zjut Edu.
 */
package com.springyounger.lottery.service.user;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.springyounger.lottery.dal.dao.PhaseDao;
import com.springyounger.lottery.dal.dataobject.LotteryPhase;
import com.springyounger.lottery.dal.dataobject.LotteryPrizeQuota;
import com.springyounger.lottery.dal.dataobject.LotteryQuota;
import com.springyounger.lottery.dal.dataobject.LotteryStatistical;
import com.springyounger.lottery.dal.dataobject.LotteryWinner;
import com.springyounger.lottery.dal.dataobject.ResultInfo;

/**
 * TODO Comment of PhaseService
 * 
 * @author springyounger
 */
public class PhaseService {
	private Logger logger = Logger.getLogger(PhaseService.class);
	public static final String NO_WIN = "0"; // 未中奖
	public final static String WIN = "1"; // 中奖
	private PhaseDao phaseDao;
	private TransactionTemplate transactionTemplate;

	/**
	 * 获取活动列表
	 * 
	 * @return
	 */
	public List<LotteryPhase> getPhases() {
		try {
			return phaseDao.getPhases();
		} catch (Exception e) {
			logger.error("获取活动列表失败!", e);
			return null;
		}
	}

	/**
	 * 获取所有的活动
	 * 
	 * @return
	 */
	public List<LotteryPhase> getPhases(int pageIndex, int pageSize) {
		try {
			return phaseDao.getPhases(pageIndex, pageSize);
		} catch (Exception e) {
			logger.error("获取活动列表失败!", e);
			return null;
		}
	}

	/**
	 * 获取活动的总数
	 * 
	 * @return
	 */
	public int getAllPhaseCount() {
		try {
			return phaseDao.getAllPhaseCount();
		} catch (Exception e) {
			logger.error("活动的总数失败", e);
			return 0;
		}
	}

	/**
	 * 根据Id获取活动
	 * 
	 * @param phaseId
	 * @return
	 */
	public LotteryPhase getPhaseById(int phaseId) {
		try {
			return phaseDao.getPhaseById(phaseId);
		} catch (Exception e) {
			logger.error("根据Id获取活动失败", e);
			return null;
		}
	}

	/**
	 * 创建活动
	 * 
	 * @param phase
	 * @return
	 */
	public boolean insertPhase(LotteryPhase phase) {
		try {
			phaseDao.insertPhase(phase);
			return true;
		} catch (Exception e) {
			logger.error("创建活动失败", e);
			return false;
		}
	}

	/**
	 * 更新活动
	 * 
	 * @param phase
	 * @return
	 */
	public boolean updatePhase(LotteryPhase phase) {
		try {
			if ((phaseDao.updatePhase(phase)) > 0) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			logger.error("更新活动失败", e);
			return false;
		}

	}

	/**
	 * 删除活动和对应的奖品
	 * 
	 * @param phaseId
	 * @return
	 */
	public void deletePhaseById(final int phaseId) {
		getTransactionTemplate().execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus status) {
				// 可以考虑增加删除活动题目
				boolean success = true;
				try {
					logger.info("删除活动");
					phaseDao.deletePhaseById(phaseId);
				} catch (Exception e) {
					logger.error("删除活动失败", e);
					success = false;
					status.setRollbackOnly();
				}

				try {
					logger.info("删除活动奖品");
					phaseDao.deletePrizeByPhaseId(phaseId);
				} catch (Exception e) {
					logger.error("删除活动奖品失败", e);
					success = false;
					status.setRollbackOnly();
				}
				return success;
			}
		});
	}

	/**
	 * 获取已存在活动
	 * 
	 * @param phaseName
	 * @return
	 */
	public boolean isExistPhase(String phaseName) {
		try {
			if (phaseDao.isExistPhase(phaseName) > 0) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			logger.error("获取已存在活动失败", e);
			return false;
		}
	}

	/**
	 * 获取抽奖配额
	 * 
	 * @param quota
	 * @return
	 */
	public LotteryQuota getLotteryQuota(LotteryQuota quota) {
		try {
			return phaseDao.getLotteryQuota(quota);
		} catch (Exception e) {
			logger.error("获取抽奖配额失败!", e);
			return null;
		}
	}

	/**
	 * 创建抽奖配额
	 * 
	 * @param quota
	 * @return
	 */
	public boolean insertLotteryQuota(LotteryQuota quota) {
		try {
			phaseDao.insertLotteryQuota(quota);
			return true;
		} catch (Exception e) {
			logger.error("创建抽奖配额失败", e);
			return false;
		}
	}

	/**
	 * 更新抽奖配额
	 * 
	 * @param quota
	 * @return
	 */
	public boolean updateLotteryQuota(LotteryQuota quota) {
		try {
			phaseDao.updateLotteryQuota(quota);
			return true;
		} catch (Exception e) {
			logger.error("更新抽奖配额失败!", e);
			return false;
		}
	}

	/**
	 * 中奖处理
	 * 
	 * @param winner
	 * @return
	 */
	public ResultInfo lotteryAction(LotteryWinner winner, Date grantDate) {
		ResultInfo resultInfo = new ResultInfo();
		// 奖品列表
		List<LotteryPrizeQuota> prizes = new ArrayList<LotteryPrizeQuota>();
		prizes = getPrizes(winner.getPhaseId(), grantDate);

		LotteryPhase lotteryPhase = phaseDao.getPhaseById(winner.getPhaseId());
		// 参与人数
		int participats = lotteryPhase.getExceptParticiants();
		if (null == prizes || prizes.size() == 0) {
			// 没有奖品
			resultInfo.setType(PhaseService.NO_WIN);
			return resultInfo;
		}
		// 随机数
		BigDecimal random = getRandomNumber();
		// 奖品随机排列
		int prizeRandom[] = getPrizeRandom(prizes.size());
		// 遍历所有奖品
		for (int i = 0; i < prizes.size(); i++) {
			// 随机选取奖品
			LotteryPrizeQuota prize = prizes.get(prizeRandom[i]);
			// 随机数和中奖概率比较
			if (random.compareTo(getProbability(prize.getPrizeAmount(),
					participats)) == -1) {
				// 中奖处理
				// return checkAndCreateLottery(winner, prize);
				LotteryPrizeQuota prizeQuota = phaseDao
						.getLotteryPrizeQuota(prize.getPrizeQuotaId());
				// 查看是否有配额
				if (prizeQuota.getAvaliableCount() > 0) {
					// 中奖信息
					winner.setLotteryDate(new Date());
					winner.setPrizeId(prize.getPrizeId());
					// 更新配额
					prize.setAvaliableCount(prize.getAvaliableCount() - 1);

					// 创建中奖者和更新奖品配额操作
					ResultInfo info = creatAndUpdateLottery(winner, prize);
					if (info.getType().equals(PhaseService.WIN)) {
						// 设置中奖信息
						info.setType(PhaseService.WIN);
						LotteryWinner lotteryWinner = (LotteryWinner) info
								.getObject();
						prize.setWinnerId(lotteryWinner.getWinnerId());
						info.setObject(prize);
						return info;
					}
				} else {
					continue;
				}
			}
		}
		// 没有中奖
		resultInfo.setType(PhaseService.NO_WIN);
		return resultInfo;
	}

	/**
	 * 获取奖品列表(级别从高到低)
	 * 
	 * @param phaseId
	 * @return
	 */
	private List<LotteryPrizeQuota> getPrizes(int phaseId, Date grantDate) {
		try {
			return phaseDao.getPrizes(phaseId, grantDate);
		} catch (Exception e) {
			logger.error("获取奖品列表失败!", e);
			return null;
		}
	}

	/**
	 * 生成随机数
	 * 
	 * @return
	 */
	private BigDecimal getRandomNumber() {
		BigDecimal random = BigDecimal.valueOf(new Random().nextDouble());
		return (random.compareTo(BigDecimal.ZERO) == -1) ? BigDecimal.ZERO
				: random;
	}

	/**
	 * 生成不同的随机数
	 * 
	 * @param prizeSize
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private int[] getPrizeRandom(int prizeSize) {
		int prizeRandom[] = new int[prizeSize];
		Random random = new Random(System.currentTimeMillis());
		// 插入顺序的set
		Set set = new LinkedHashSet();
		while (true) {
			int ran = random.nextInt(prizeSize);
			set.add(ran);
			if (set.size() == prizeSize) {
				break;
			}
		}
		Iterator it = set.iterator();
		int i = 0;
		while (it.hasNext()) {
			prizeRandom[i++] = Integer.parseInt(it.next().toString());
		}
		return prizeRandom;
	}

	/**
	 * 计算中奖概率
	 * 
	 * @param numerator
	 * @param denumberator
	 * @return
	 */
	private BigDecimal getProbability(int numerator, int denumberator) {
		if (numerator <= 0 || denumberator <= 0) {
			return BigDecimal.ZERO;
		}
		BigDecimal probability = BigDecimal.valueOf(numerator).divide(
				BigDecimal.valueOf(denumberator), 16, RoundingMode.HALF_UP);
		return (probability.compareTo(BigDecimal.ZERO) == -1) ? BigDecimal.ZERO
				: probability;
	}

	// /**
	// * 中奖处理
	// *
	// * @param winner
	// * @param quota
	// * @return
	// */
	// private ResultInfo checkAndCreateLottery(LotteryWinner winner,
	// LotteryPrizeQuota prize) {
	// ResultInfo resultInfo = new ResultInfo();
	//
	// //奖品配额
	// LotteryPrizeQuota prizeQuota =
	// phaseDao.getLotteryPrizeQuota(prize.getPrizeQuotaId());
	// if (null == prizeQuota) {
	// //没有奖品
	// resultInfo.setType(PhaseService.NO_WIN);
	// return resultInfo;
	// }
	//
	// if (prizeQuota.getAvaliableCount() > 0) {
	// //中奖信息
	// winner.setLotteryDate(new Date());
	// winner.setPrizeId(prize.getPrizeId());
	// //更新配额
	// prize.setAvaliableCount(prize.getAvaliableCount() - 1);
	//
	// //创建中奖者和更新奖品配额操作
	// ResultInfo info = creatAndUpdateLottery(winner, prize);
	// if (info.getType().equals(PhaseService.WIN)) {
	// //设置中奖信息
	// info.setType(PhaseService.WIN);
	// LotteryWinner lotteryWinner = (LotteryWinner) info.getObject();
	// prize.setWinnerId(lotteryWinner.getWinnerId());
	// info.setObject(prize);
	// return info;
	// }
	// }
	// resultInfo.setType(PhaseService.NO_WIN);
	// return resultInfo;
	// }

	/**
	 * 更新配额和创建中奖
	 * 
	 * @param winner
	 * @param prize
	 * @return
	 */
	private ResultInfo creatAndUpdateLottery(final LotteryWinner winner,
			final LotteryPrizeQuota prize) {
		ResultInfo resultInfo = (ResultInfo) getTransactionTemplate().execute(
				new TransactionCallback() {
					// 事务处理
					public Object doInTransaction(TransactionStatus status) {
						ResultInfo info = new ResultInfo();
						info.setType(PhaseService.WIN);
						// 更新配额
						try {
							phaseDao.updateLotteryPrizeQuota(prize);
						} catch (Exception e) {
							logger.error("更新奖品配额失败!", e);
							info.setType(PhaseService.NO_WIN);
							// 回滚
							status.setRollbackOnly();
						}

						// 创建中奖名单
						try {
							LotteryWinner lotteryWinner = new LotteryWinner();
							lotteryWinner = phaseDao
									.insertLotteryWinner(winner);
							info.setObject(lotteryWinner);
						} catch (Exception e) {
							logger.error("创建中奖者失败!", e);
							info.setType(PhaseService.NO_WIN);
							status.setRollbackOnly();
						}
						return info;
					}
				});
		return resultInfo;
	}

	/**
	 * 获取最近中奖名单
	 * 
	 * @param phaseId
	 * @param topSize
	 * @return
	 */
	public List<LotteryWinner> getLatestWinner(int phaseId, int topSize) {
		try {
			return phaseDao.getLatestWinner(phaseId, topSize);
		} catch (Exception e) {
			logger.error("获取最近中奖名单失败", e);
			return null;
		}
	}

	/**
	 * 获取指定用户中奖数量
	 * 
	 * @param userid
	 * @param phaseId
	 * @return
	 */
	public int getAllWinnerCountById(int userid, int phaseId) {
		try {
			return phaseDao.getAllWinnerCountById(userid, phaseId);
		} catch (Exception e) {
			logger.error("获取指定用户中奖数量失败", e);
			return 0;
		}
	}

	/**
	 * 获取指定用户中奖名单
	 * 
	 * @param userid
	 * @param phaseId
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 */
	public List<LotteryWinner> getWinnerById(int userid, int phaseId,
			int pageIndex, int pageSize) {
		try {
			return phaseDao.getWinnerById(userid, phaseId, pageIndex, pageSize);
		} catch (Exception e) {
			logger.error("获取指定用户中奖名单失败", e);
			return null;
		}
	}

	/**
	 * 获取活动统计
	 * 
	 * @param phaseId
	 * @return
	 */
	public List<LotteryStatistical> getStat(int phaseId) {
		try {
			return phaseDao.getStat(phaseId);
		} catch (Exception e) {
			logger.error("获取活动统计失败", e);
			return null;
		}

	}

	/**
	 * 批量统计活动人数
	 * 
	 * @param statList
	 * @return
	 */
	public boolean batchInsertStat(List<LotteryStatistical> statList) {
		try {
			if (logger.isInfoEnabled()) {
				logger.info("开始统计活动人数");
			}

			phaseDao.batchInsertStat(statList);

			if (logger.isInfoEnabled()) {
				logger.info("统计活动人数结束");
			}
			return true;
		} catch (Exception e) {
			logger.error("批量创建统计数据失败", e);
			return false;
		}
	}

	/**
	 * 获取统计人数
	 * 
	 * @param phaseId
	 * @param prizeLevel
	 * @param lotteryDate
	 * @return
	 */
	public LotteryStatistical getStatValue(int phaseId, String prizeLevel,
			Date lotteryDate) {
		try {
			return phaseDao.getStatValue(phaseId, prizeLevel, lotteryDate);
		} catch (Exception e) {
			logger.error("获取统计人数失败", e);
			return null;
		}
	}

	/**
	 * 根据时间获取统计人数
	 * 
	 * @param phaseId
	 * @param winDate
	 * @return
	 */
	public boolean isExistStat(int phaseId, Date winDate) {
		try {
			if (phaseDao.getStatByDate(phaseId, winDate) > 0) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			logger.error("根据时间获取统计人数失败", e);
			return false;
		}
	}

	/**
	 * @param phaseDao
	 *            the phaseDao to set
	 */
	public void setPhaseDao(PhaseDao phaseDao) {
		this.phaseDao = phaseDao;
	}

	/**
	 * @return the transactionTemplate
	 */
	public TransactionTemplate getTransactionTemplate() {
		return transactionTemplate;
	}

	/**
	 * @param transactionTemplate
	 *            the transactionTemplate to set
	 */
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
}
